import { RepoLink, Link, Warning } from '@brillout/docpress'
import { ViteLazyTranspilingContradiction } from '../../components'

## Installation

You can use [Markdown](https://en.wikipedia.org/wiki/Markdown) by adding one of the following [Vite plugins](https://vitejs.dev/plugins/).

### Vue

Markdown plugins compatible with Vue:
 - [`@mdx-js/rollup`](https://mdxjs.com/packages/rollup/)
 - [`unplugin-vue-markdown`](https://github.com/unplugin/unplugin-vue-markdown)
 - [`vite-plugin-md`](https://github.com/antfu/vite-plugin-md)

Example:
 - <RepoLink path='/examples/vue-full/vite.config.ts' />
 - <RepoLink path='/examples/vue-full/pages/markdown/+Page.md' />


### React

Markdown plugins compatible with React:
 - [`@cyco130/vite-plugin-mdx`](https://github.com/cyco130/vite-plugin-mdx/)
 - [`@mdx-js/rollup`](https://mdxjs.com/packages/rollup/)

Example:
 - <RepoLink path='/examples/react-full/vite.config.ts' />
 - <RepoLink path='/examples/react-full/pages/markdown/+Page.mdx' />


## Metadata

There are several techniques for defining metadata (e.g. the date and author of a page).

The preferred technique depends on whether you want to define global or local metadata.

#### Global metadata

> **What is global metadata?** For example, you want to show a list of all your blog posts always on the left side of your website.
> ```
> 2024-01-01 New Year 2024 Resolution
> 2023-12-20 Wrapping up 2023
> 2023-06-15 My summer 2023
> ```
> Because this list is shown on the left of every page, the publishing date and title of all blog posts is needed for rendering any page: the metadata needs to be accessible *globally*.

For global metadata, we recommend:
- <Link href="#with-a-metadata-js-file" />
- <Link href="#with-a-custom-setting-eager" />

<Warning>
 You may be tempted to use [`import.meta.glob()`](https://vitejs.dev/guide/features.html#glob-import) to retrieve metadata defined inside all `+Page.md` files, but we discourage this approach: loading all `+Page.md` files at once <ViteLazyTranspilingContradiction />.
</Warning>

#### Local metadata

> **What is local metadata?**  For example, you want to show detailed information below a blog post, such as the author's name. This metadata is shown only for that page and, therefore, needs to be accessible only *locally*.

For local metadata, we recommend:
- <Link href="#with-a-custom-setting" />
- <Link href="#with-frontmatter" />


### With a `metadata.js` file

A simple way to define metadata is to define a `metadata.js` file that contains <Link href="#global-metadata">global metadata</Link>.

```ts
// /pages/metadata.ts

// This metadata is available to every page
export const metadata = [
  {
    url: '/blog/introducing-vike',
    title: 'Introducing Vike',
    date: new Date('2024-01-01')
  },
  {
    url: '/blog/v1',
    title: 'v1.0.0 release',
    date: new Date('2025-07-01')
  }
]
```

```tsx
// /pages/+Layout.tsx

import React from 'react'
import { metadata } from './metadata'

export function Layout({ children }: { children: React.ReactNode }) {
  // Current URL
  const { urlPathname } = usePageContext()
  // The page's metadata
  const { title } = metadata.find(({ url }) => url === urlPathname)

  return (
    <>
      {/* Show the list of blog posts */}
      <LeftSidebar>
        <p>Blog posts:</p>
        <ul>
          {metadata.map(({ title, url, date }) => (
            <li>
              <a href={url}>{data + title}</a>
            </li>
          ))}
        </ul>
      </LeftSidebar>

      {/* The page's content */}
      <Content>
        <h1>{title}</h1>
        {/* children is pageContext.Page which is the component defined by +Page.md */}
        {children}
      </Content>
    </>
  )
}
```

> See also:
> - <Link href="/Layout" />
> - <Link href="/usePageContext" />

```md
// /pages/blog/introducing-vike/+Page.md

We're thrilled to officially introduce Vike.
```

```md
// /pages/blog/v1/+Page.md

The `v1.0.0` release signals that Vike is ready for prime time: it now includes
all essentials you'd expect from a frontend framework with a robust design.
```


### With a custom setting (eager)

You can use <Link href="/meta">`meta`</Link> to create a custom setting for defining <Link href="#global-metadata">global metadata</Link>.

```yaml
/pages/+config.ts
/pages/+onCreateGlobalContext.server.ts
/pages/+Layout.tsx
/pages/2024-new-year/+Page.md
/pages/2024-new-year/+metadata.ts
```

```ts
// /pages/+config.ts

import type { Config } from 'vike/types'

export default {
  meta: {
    // Create +metadata setting
    metadata: {
      // Make +metadata available to all pages
      eager: true,
      env: {
        server: true,
        // Instead of `client: true`, we use onCreateGlobalContext() with passToClient to
        // be able to determine exactly what metadata is sent to the client-side.
        client: false
      }
    }
  },
  passToClient: [
    // Make globalContext.posts available on the client-side
    'posts'
  ]
} satisfies Config
```

> When setting `eager: true` the setting is available globally to all pages.

```ts
// /pages/2024-new-year/+metadata.ts

export const metadata = {
  title: 'New Year 2024 Resolution'
}
```

> Unlike in the example <Link href="#with-a-custom-setting">below</Link> you cannot define `+metadata` inside `+Page.md`, because `+Page.md` is <Link href="/lazy-transpiling">only loaded when rendering that page</Link>. Consequently, the content of `+Page.md` isn't available when rendering another page.

```ts
// /pages/+onCreateGlobalContext.server.ts
// Environment: server

import type { GlobalContextServer } from 'vike/types'

export async function onCreateGlobalContext(globalContext: GlobalContextServer) {
  const pages = globalContext.pages
  const posts = Object.values(pages).map((page) => {
    const { metadata } = page.config
    const post = {
      url: page.route,
      title: metadata.title
    }
    return post
  })
  globalContext.posts = posts
}

declare global {
  namespace Vike {
    interface GlobalContext {
      posts: {
        url: string,
        title: string,
      }[]
    }
  }
}
```

> See also:
> - <Link href="/globalContext#pages">API > `globalContext.pages`</Link>
> - <Link href="/onCreateGlobalContext" />

```ts
// pages/+config.ts

import type { Config } from 'vike/types'

export default {
   passToClient: ['posts']
} satisfies Config
```

```tsx
// /pages/+Layout.tsx
// Environment: server & client

import React from 'react'
import { usePageContext } from 'vike-react/usePageContext' // or vike-{vue,solid}

export function Layout({ children }: { children: React.ReactNode }) {
  const pageContext = usePageContext()
  const { posts } = pageContext.globalContext
  return (
    <>
      {/* Show the list of blog posts */}
      <LeftSidebar>
        <p>Blog posts:</p>
        <ul>
          {posts.map((post) => (
            <li>
              <a href={post.url}>{post.title}</a>
            </li>
          ))}
        </ul>
      </LeftSidebar>

      {/* The page's content */}
      <Content>
        <h1>{title}</h1>
        {/* children is pageContext.Page which is the component defined by +Page.md */}
        {children}
      </Content>
    </>
  )
}
```

> See also:
> - <Link href="/Layout" />
> - <Link href="/usePageContext" />
> - <Link href="/pageContext#globalContext">API > `pageContext.globalContext`</Link>

### With a custom setting

You can use <Link href="/meta">`meta`</Link> to create a custom setting for defining <Link href="#local-metadata">local metadata</Link>.

```mdx
// /pages/2024-new-year/+Page.mdx

export const metadata = {
  author: {
    firstName: 'John',
    lastName: 'Smith',
    country: 'England'
  }
}

## Some Markdown

This page uses [markdown](https://en.wikipedia.org/wiki/Markdown).
```

> [MDX](https://mdxjs.com/) allows you to export JavaScript values in `.mdx` files.

> Usually, Vike forbids `+Page.js` files to have "side exports": the `+Page.js` should only export the value of the <Link href="/Page">`Page` setting</Link>.
> But, for improved DX, Vike allows markdown files (such as `+Page.mdx`) to export the value of <Link href="/settings">other settings</Link>.

```ts
// /pages/+config.ts

import type { Config } from 'vike/types'

// Create +metadata setting
export default {
  meta: {
    metadata: {
      env: { server: true, client: true }
    }
  }
} satisfies Config
```


### With frontmatter

Some markdown processors have support for a so-called *frontmatter*:

```mdx
---
title: A Markdown Page
author: John Smith
---

## Some Markdown

This page uses [markdown](https://en.wikipedia.org/wiki/Markdown).
```

You can use such frontmatter to define <Link href="#local-metadata">local metadata</Link>.

<Warning>
 We discourage using frontmatter for defining <Link href="#global-metadata">global metadata</Link>, because loading all `+Page.md` files at once <ViteLazyTranspilingContradiction />.
</Warning>


The markdown processor exposes the data defined by the frontmatter as an export, for example `export { frontmatter }`. You can access it by using <Link href="/meta">`meta`</Link> to define a `+frontmatter` setting (or whatever the name of the export is).

```ts
// pages/+config.ts

export default {
  meta: {
    // Create new setting +frontmatter
    frontmatter: {
      env: { server: true, client: true }
    }
  }
} satisfies Config
```

You can then use <Link href="/pageContext#config">`pageContext.config`</Link> to access it:

```tsx
// /pages/+Layout.tsx

import React from 'react'
import { usePageContext } from 'vike-react/usePageContext' // or vike-{vue,solid}

export function Layout({ children }: { children: React.ReactNode }) {
  const pageContext = usePageContext()
  const { frontmatter } = pageContext.config
  return (
    <>
      <h1>{frontmatter.title}</h1>
      {children}
      <footer>
        <p>Written by {frontmatter.author}.</p>
      </footer>
    </>
  )
}
```

> See also:
> - <Link href="/Layout" />
> - <Link href="/usePageContext" />

## See also

- <Link href="/head-tags" />
